from django.shortcuts import render
from django.views import View
from decimal import Decimal
from django import http
from django_redis import get_redis_connection
from django.utils import timezone
from django.db import transaction
import logging
import json

from meiduo_mall.utils.view import LoginRequiredJsonMixin
from users.models import Address
from goods.models import SKU
from orders.models import OrderInfo, OrderGoods

# Create your views here.

# 创建日志生成器
logger = logging.getLogger('django')


class OrderCommitView(LoginRequiredJsonMixin, View):
    def post(self, request):
        # 提取参数
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        # 校验参数
        if not all([address_id, pay_method]):
            return http.JsonResponse({'code': 400, 'errmsg': '缺少必要参数'})

        if not isinstance(address_id, int):
            return http.JsonResponse({'code': 400, 'errmsg': 'address_id参数有误'})

        if not isinstance(pay_method, int):
            return http.JsonResponse({'code': 400, 'errmsg': 'pay_method参数有误'})

        # 生成订单号
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%06d' % request.user.id)

        # 使用事务解决库存不足时,返回订单表的数据的创建
        with transaction.atomic():
            save_id = transaction.savepoint()
            # 保存订单信息表数据
            order = OrderInfo.objects.create(
                order_id=order_id,
                user=request.user,
                address_id=address_id,
                total_count=0,
                total_amount=0,
                freight=Decimal(10.00),
                pay_method=pay_method
            )
            # 保存商品信息
            conn = get_redis_connection('carts')
            # data: {b'14': b'5', ....} 从redis读取的数据类型是字节
            data = conn.hgetall('carts_%s' % request.user.id)
            selected_ids = conn.smembers('selected_%s' % request.user.id)

            for sku_id in selected_ids:
                # 使用乐观锁解决订单的高并发
                while True:
                    try:
                        sku = SKU.objects.get(id=sku_id)
                    except Exception as e:
                        logger.error(e)
                        return http.JsonResponse({'code': 400, 'errmsg': '商品不存在'})

                    # 1.先读取旧数据
                    old_stock = sku.stock
                    old_sales = sku.sales
                    count = int(data[sku_id])

                    # 第一次判断,保存数据前先判断库存是否满足需求
                    if count > old_stock:
                        # 事务回滚
                        transaction.savepoint_rollback(save_id)
                        return http.JsonResponse({'code': 400, 'errmsg': '购买数量超过库存'})

                    # SKU商品库存和销量的更新
                    new_stock = old_stock - count
                    new_sales = old_sales + count

                    result = SKU.objects.filter(id=sku_id, stock=old_stock, sales=old_sales).update(
                        stock=new_stock, sales=new_sales
                    )

                    if not result:
                        continue

                    # 更新订单表的金额数据
                    order.total_amount += sku.price * count
                    order.total_count += count
                    order.save()

                    # 保存商品数据
                    OrderGoods.objects.create(
                        order_id=order_id,
                        sku=sku,
                        count=count,
                        price=sku.price
                    )

                    break

            # 更新订单表的最后总金额数据
            order.total_amount += order.freight
            order.save()
            # 取消事务
            transaction.savepoint_commit(save_id)
        # 创建管道
        pl = conn.pipeline()
        pl.hdel('carts_%s' % request.user.id, *selected_ids)
        pl.srem('selected_%s' % request.user.id, *selected_ids)
        # 执行管道
        pl.execute()

        return http.JsonResponse({'code': 0, 'errmsg': 'ok', 'order_id': order_id})


class OrderSettlementView(LoginRequiredJsonMixin, View):
    def get(self, request):
        addresses = []
        address_queryset = Address.objects.filter(user=request.user, is_deleted=False)

        for address in address_queryset:
            addresses.append({
                'id': address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'mobile': address.mobile,
                'receiver': address.receiver
            })
        skus_list = []
        conn = get_redis_connection('carts')
        data = conn.hgetall('carts_%s' % request.user.id)
        selected_ids = conn.smembers('selected_%s' % request.user.id)
        skus = SKU.objects.filter(id__in=selected_ids)
        for sku in skus:
            skus_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image_url,
                'count': int(data[str(sku.id).encode()]),
                'price': sku.price
            })

        freight = Decimal('10.00')
        context = {
            'addresses': addresses,
            'skus': skus_list,
            'freight': freight
        }

        return http.JsonResponse({'code': 0, 'errmsg': 'ok', 'context': context})

